package edu.zzuli.common.security;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

import javax.sql.DataSource;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.userdetails.User;
import org.acegisecurity.userdetails.UserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.MappingSqlQuery;

public class CustomJdbcDaoImpl extends JdbcDaoImpl {
	
	private String usersByCaidQuery;

	protected MappingSqlQuery usersByCaidMapping;
	
	protected MappingSqlQuery customAuthoritiesByUsernameMapping;

	public CustomJdbcDaoImpl() {
		super();
	}

	public String getUsersByCaidQuery() {
		return usersByCaidQuery;
	}

	public void setUsersByCaidQuery(String usersByCaidQuery) {
		this.usersByCaidQuery = usersByCaidQuery;
	}

	protected void initMappingSqlQueries() {
		super.initMappingSqlQueries();
		this.usersByCaidMapping = new UsersByCaidMapping(getDataSource());
		this.customAuthoritiesByUsernameMapping = new CustomAuthoritiesByUsernameMapping(getDataSource());
	}

	public UserDetails loadUserByCaid(String caid) throws UsernameNotFoundException, DataAccessException {
		List users = usersByCaidMapping.execute(caid);
		if (users.size() == 0) {
			throw new CustomAuthenticationException("该证书未与登录帐号绑定！",CustomAuthenticationException.CODE_CA,-2);
		}
		UserDetails user = (UserDetails) users.get(0); // contains no
		// GrantedAuthority[]
		List dbAuths = customAuthoritiesByUsernameMapping.execute(new Object[]{user.getUsername(),user.getUsername(),user.getUsername()});

		addCustomAuthorities(user.getUsername(), dbAuths);

		if (dbAuths.size() == 0) {
			throw new CustomAuthenticationException("该帐号没有任何访问权限！",CustomAuthenticationException.CODE_CA,-3);
		}

		GrantedAuthority[] arrayAuths = (GrantedAuthority[]) dbAuths.toArray(new GrantedAuthority[dbAuths.size()]);
		String returnUsername = user.getUsername();

		// if (!usernameBasedPrimaryKey) {
		// returnUsername = username;
		// }

		return new User(returnUsername, user.getPassword(), user.isEnabled(),
				true, true, true, arrayAuths);
	}

	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
		List users = usersByUsernameMapping.execute(username);
		if (users.size() == 0)
			throw new UsernameNotFoundException("User not found");
		UserDetails user = (UserDetails) users.get(0);
		List dbAuths = this.customAuthoritiesByUsernameMapping.execute(new Object[]{user.getUsername(),user.getUsername(),user.getUsername()});
		addCustomAuthorities(user.getUsername(), dbAuths);
		//if (dbAuths.size() == 0)
		//	throw new UsernameNotFoundException("User has no GrantedAuthority");
		GrantedAuthority arrayAuths[] = (GrantedAuthority[]) (GrantedAuthority[]) dbAuths
				.toArray(new GrantedAuthority[dbAuths.size()]);
		String returnUsername = user.getUsername();
		if (!isUsernameBasedPrimaryKey())
			returnUsername = username;
		return new User(returnUsername, user.getPassword(), user.isEnabled(),
				true, true, true, arrayAuths);
	}
	/**
	 * Query object to look up a user.
	 */
	protected class UsersByCaidMapping extends MappingSqlQuery {
		protected UsersByCaidMapping(DataSource ds) {
			super(ds, usersByCaidQuery);
			declareParameter(new SqlParameter(Types.VARCHAR));
			compile();
		}

		protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
			String username = rs.getString(1);
			String password = rs.getString(2);
			boolean enabled = rs.getBoolean(3);
			UserDetails user = new User(username,password,enabled,true,true,true,
					new GrantedAuthority[] { new GrantedAuthorityImpl("HOLDER") });
			return user;
		}
	}
	
	protected class CustomAuthoritiesByUsernameMapping extends MappingSqlQuery {

        protected Object mapRow(ResultSet rs, int rownum)throws SQLException {
            String roleName = CustomJdbcDaoImpl.this.getRolePrefix() + rs.getString(2);
            GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
            return authority;
        }

        protected CustomAuthoritiesByUsernameMapping(DataSource ds) {
            super(ds, CustomJdbcDaoImpl.this.getAuthoritiesByUsernameQuery());
            declareParameter(new SqlParameter(Types.VARCHAR));
            declareParameter(new SqlParameter(Types.VARCHAR));
            declareParameter(new SqlParameter(Types.VARCHAR));
            compile();
        }
    }
}
